/// ------------------------------------------------------------------------------------------------------------------------------------
///
/// MIT License
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
///
/// Copyright (c) 2024 ycz. All rights reserved.
///
/// Created by ycz on 24-7-15.
///
/// @file  y_alg.h
///
/// @brief
///     一种应用于嵌入式的简单算法工具
///
/// ------------------------------------------------------------------------------------------------------------------------------------



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 防止当前头文件被重复引用
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifndef _Y_ALG_H
#define _Y_ALG_H



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 头文件
/// ------------------------------------------------------------------------------------------------------------------------------------

#include <stdint.h>
#include <stdbool.h>
#include <float.h>



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 兼容 c++
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifdef __cplusplus
extern "C" {
#endif



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义
/// ------------------------------------------------------------------------------------------------------------------------------------

#define Y_ALG_MAJOR 0  ///< 主版本     ( 主架构变化 )
#define Y_ALG_MINOR 1  ///< 次版本     ( 单个功能增加或修改 )
#define Y_ALG_PATCH 1  ///< 补丁版本   ( bug 修复 )

#define Y_PI        3.14159265358979  ///< PI



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 结构体
/// ------------------------------------------------------------------------------------------------------------------------------------

#pragma pack(1)  // 设置结构体 1 字节对齐

/// 单精度

/// 卡尔曼参数结构体
typedef struct {
    float last_p;  ///< 上次估算协方差
    float now_p;   ///< 当前估算协方差
    float out;     ///< 卡尔曼滤波器输出
    float kg;      ///< 卡尔曼增益
    float q;       ///< 过程噪声协方差  q 增大，动态响应变快，收敛稳定性变坏
    float r;       ///< 观测噪声协方差  r 增大，动态响应变慢，收敛稳定性变好
} ALG_KALMAN_F_st;

/// IIR 参数结构体
typedef struct {
    float arr[2];  ///< 延迟缓存数组
    float a[2];    ///< 数组a
    float b[3];    ///< 数组b
} ALG_IIR_F_st;

/// 窗口参数结构体
typedef struct {
    uint16_t size;   ///< 窗口大小
    uint16_t slide;  ///< 窗口滑动大小
    uint16_t index;  ///< 当前操作索引 从 1 开始
    float   *arr;    ///< 窗口数组 单精度
} ALG_WINDOW_F_st;


/// 双精度

/// 卡尔曼参数结构体
typedef struct {
    double last_p;  ///< 上次估算协方差
    double now_p;   ///< 当前估算协方差
    double out;     ///< 卡尔曼滤波器输出
    double kg;      ///< 卡尔曼增益
    double q;       ///< 过程噪声协方差  q 增大，动态响应变快，收敛稳定性变坏
    double r;       ///< 观测噪声协方差  r 增大，动态响应变慢，收敛稳定性变好
} ALG_KALMAN_D_st;

/// IIR 参数结构体
typedef struct {
    double arr[2];  ///< 延迟缓存数组
    double a[2];    ///< 数组a
    double b[3];    ///< 数组b
} ALG_IIR_D_st;

/// 窗口参数结构体
typedef struct {
    uint16_t size;   ///< 窗口大小
    uint16_t slide;  ///< 窗口滑动大小
    uint16_t index;  ///< 当前操作索引 从 1 开始
    double  *arr;    ///< 窗口数组 双精度
} ALG_WINDOW_D_st;

#pragma pack()  // 恢复结构体默认对其方式



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 函数 API
/// ------------------------------------------------------------------------------------------------------------------------------------

void y_alg_print_version();  ///< 打印模块版本号

/// 单精度
float            y_alg_trunc_f(float value, uint8_t num);  ///< 截断小数
// 统计
uint16_t         y_alg_get_max_index_f(float *arr, uint16_t size);                          ///< 求最大值数值下标
uint16_t         y_alg_get_min_index_f(float *arr, uint16_t size);                          ///< 求最小值数值下标
float            y_alg_get_max_f(float *arr, uint16_t size);                                ///< 求最大值
float            y_alg_get_min_f(float *arr, uint16_t size);                                ///< 求最小值
float            y_alg_get_mid_f(float *arr, uint16_t size);                                ///< 求中位值
float            y_alg_get_sum_f(float *arr, uint16_t size);                                ///< 求和
float            y_alg_get_avg_f(float *arr, uint16_t size);                                ///< 求平均值
float            y_alg_get_var_f(float *arr, uint16_t size);                                ///< 求方差
float            y_alg_get_sd_f(float *arr, uint16_t size);                                 ///< 求标准差
float            y_alg_get_trimmean_f(float *arr, uint16_t size);                           ///< 去掉最大值最小值后求平均
float            y_alg_get_weighted_avg_f(float *arr, uint16_t size, float *weighted_arr);  ///< 求加权平均值
// 滤波
float            y_alg_filter_limiting_f(float now_value, float last_value, float threshold);           ///< 限幅滤波
float            y_alg_filter_first_order_low_f(float now_value, float last_value, float a);            ///< 一阶低通滤波
float            y_alg_filter_first_order_high_f(float now_value, float last_value, float a);           ///< 一阶高通滤波
float            y_alg_filter_first_order_complementary_f(float low_value, float high_value, float a);  ///< 一阶互补滤波
float            y_alg_filter_kalman_f(ALG_KALMAN_F_st *kalman, float now_value);                       ///< 卡尔曼滤波
float            y_alg_filter_iir_f(ALG_IIR_F_st *iir, float now_value, uint16_t fs, float fc);         ///< IIR滤波 无限长冲激响应响应滤波器
// 窗口
ALG_WINDOW_F_st *y_alg_window_create_f(uint16_t size, uint16_t slide);                     ///< 创建窗口
bool             y_alg_window_destroy_f(ALG_WINDOW_F_st *win);                             ///< 销毁窗口
bool             y_alg_window_is_empty_f(ALG_WINDOW_F_st *win);                            ///< 窗口数据是否为空
bool             y_alg_window_is_full_f(ALG_WINDOW_F_st *win);                             ///< 窗口数据是否为满
bool             y_alg_window_add_f(ALG_WINDOW_F_st *win, float value);                    ///< 往窗口添加值
bool             y_alg_window_add_arr_f(ALG_WINDOW_F_st *win, float *arr, uint16_t size);  ///< 往窗口添加数组
bool             y_alg_window_del_f(ALG_WINDOW_F_st *win);                                 ///< 从窗口删除值 从后往前删除
bool             y_alg_window_clear_f(ALG_WINDOW_F_st *win);                               ///< 清空窗口值
void             y_alg_window_print_f(ALG_WINDOW_F_st *win);                               ///< 打印窗口值


/// 双精度
double           y_alg_trunc_d(double value, uint8_t num);  ///< 截断小数
// 统计
uint16_t         y_alg_get_max_index_d(double *arr, uint16_t size);                           ///< 求最大值数值下标
uint16_t         y_alg_get_min_index_d(double *arr, uint16_t size);                           ///< 求最小值数值下标
double           y_alg_get_max_d(double *arr, uint16_t size);                                 ///< 求最大值
double           y_alg_get_min_d(double *arr, uint16_t size);                                 ///< 求最小值
double           y_alg_get_mid_d(double *arr, uint16_t size);                                 ///< 求中位值
double           y_alg_get_sum_d(double *arr, uint16_t size);                                 ///< 求和
double           y_alg_get_avg_d(double *arr, uint16_t size);                                 ///< 求平均值
double           y_alg_get_var_d(double *arr, uint16_t size);                                 ///< 求方差
double           y_alg_get_sd_d(double *arr, uint16_t size);                                  ///< 求标准差
double           y_alg_get_trimmean_d(double *arr, uint16_t size);                            ///< 去掉最大值最小值后求平均
double           y_alg_get_weighted_avg_d(double *arr, uint16_t size, double *weighted_arr);  ///< 求加权平均值
// 滤波
double           y_alg_filter_limiting_d(double now_value, double last_value, double threshold);           ///< 限幅滤波
double           y_alg_filter_first_order_low_d(double now_value, double last_value, double a);            ///< 一阶低通滤波
double           y_alg_filter_first_order_high_d(double now_value, double last_value, double a);           ///< 一阶高通滤波
double           y_alg_filter_first_order_complementary_d(double low_value, double high_value, double a);  ///< 一阶互补滤波
double           y_alg_filter_kalman_d(ALG_KALMAN_D_st *kalman, double now_value);                         ///< 卡尔曼滤波
double           y_alg_filter_iir_d(ALG_IIR_D_st *iir, double now_value, uint16_t fs, double fc);          ///< IIR滤波 无限长冲激响应响应滤波器
// 窗口
ALG_WINDOW_D_st *y_alg_window_create_d(uint16_t size, uint16_t slide);                      ///< 创建窗口
bool             y_alg_window_destroy_d(ALG_WINDOW_D_st *win);                              ///< 销毁窗口
bool             y_alg_window_is_empty_d(ALG_WINDOW_D_st *win);                             ///< 窗口数据是否为空
bool             y_alg_window_is_full_d(ALG_WINDOW_D_st *win);                              ///< 窗口数据是否为满
bool             y_alg_window_add_d(ALG_WINDOW_D_st *win, double value);                    ///< 往窗口添加值
bool             y_alg_window_add_arr_d(ALG_WINDOW_D_st *win, double *arr, uint16_t size);  ///< 往窗口添加数组
bool             y_alg_window_del_d(ALG_WINDOW_D_st *win);                                  ///< 从窗口删除值 从后往前删除
bool             y_alg_window_clear_d(ALG_WINDOW_D_st *win);                                ///< 清空窗口值
void             y_alg_window_print_d(ALG_WINDOW_D_st *win);                                ///< 打印窗口值



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 条件编译结尾
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifdef __cplusplus
}
#endif  // __cplusplus 兼容 c++
#endif  // _Y_ALG_H 防止当前头文件被重复引用